package org.janusproject.demos.acl.cnp.role;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.janusproject.acl.protocol.ProtocolResult;
import org.janusproject.acl.protocol.ProtocolState;
import org.janusproject.acl.protocol.cnp.FipaContractNetProtocol;
import org.janusproject.kernel.address.AgentAddress;
import org.janusproject.kernel.crio.core.Role;
import org.janusproject.kernel.status.Status;
import org.janusproject.kernel.status.StatusFactory;

public class ContractNetRequester extends Role {
	
	private FipaContractNetProtocol contractNetProtocol;
	private List<ProtocolResult> proposals;
	private List<AgentAddress> selectedParticipants;
	private List<ProtocolResult> results;
	
	private State state;
	
	public Status activate(Object... parameters) {
		
		for (Object parameter : parameters) {
			if (parameter instanceof FipaContractNetProtocol) {
				contractNetProtocol = (FipaContractNetProtocol) parameter;
				state = State.SENDING_CALL_FOR_PROPOSAL;
				return StatusFactory.ok(this);
			}
		}
		
		return StatusFactory.cancel(this);
	}
	
	@Override
	public Status live() {
		state = Request();
		return StatusFactory.ok(this);
	}
	
	private State Request() {
		
		if( contractNetProtocol.hasFailed() ){
			leaveMe();
		}
		
		switch (state) 
		{
			case SENDING_CALL_FOR_PROPOSAL: 
			{	
				contractNetProtocol.callForProposal("description of the task");
				
				//requestProtocol.cancel("@++");
				
				log( "cfp sent");
				
				return State.WAITING_ALL_PROPOSALS;
			}
			case WAITING_ALL_PROPOSALS:
			{
				proposals = contractNetProtocol.getAllProposals();
				
				if( proposals != null ) {
					log( "all proposals received" );
					
					if (proposals.size() == 0) // nobody has accepted the task
						return State.REFUSED;
					
					selectedParticipants = new ArrayList<AgentAddress>();
					selectedParticipants.add(proposals.get(0).getAuthor()); // arbitrary, need to use capacity
					
					contractNetProtocol.acceptProposals(selectedParticipants, "thanks");
					log( "all proposals answered" );
					
					return State.WAITING_ALL_RESULTS;
				}
				else {
					return this.state;
				}
			}
			case WAITING_ALL_RESULTS:
			{
				results = contractNetProtocol.getResults();
				
				if( results != null ) {
					log( "results received");
					return State.DONE;
				}
				else {
					return this.state;
				}
			}
			case DONE:
			{
				leaveMe();
			}
		default:
			return this.state;
		}
	}	
	
	private void log(String str){
		Logger.getAnonymousLogger().log(Level.INFO, "[" + getPlayer() + "] : " + str);
	}
	
	private enum State implements ProtocolState {
		NOT_STARTED,
		SENDING_CALL_FOR_PROPOSAL,
		WAITING_ALL_PROPOSALS,
		WAITING_ALL_RESULTS,
		CANCELING,
		CANCELED,
		REFUSED,
		DONE;
	}

}
